<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>requestIdelCallback</title>
</head>
<body>
      <div >

        总结
        一些低优先级的任务可使用 requestIdleCallback 等浏览器不忙的时候来执行，同时因为时间有限，它所执行的任务应该尽量是能够量化，细分的微任务（micro task）
        
        因为它发生在一帧的最后，此时页面布局已经完成，所以不建议在 requestIdleCallback 里再操作 DOM，这样会导致页面再次重绘。DOM 操作建议在 rAF 中进行。同时，操作 DOM 所需要的耗时是不确定的，因为会导致重新计算布局和视图的绘制，所以这类操作不具备可预测性。
        
        Promise 也不建议在这里面进行，因为 Promise 的回调属性 Event loop 中优先级较高的一种微任务，会在 requestIdleCallback 结束时立即执行，不管此时是否还有富余的时间，这样有很大可能会让一帧超过 16 ms。
      

      </div>
      <div >------------------------------------------------------------------------------</div>
      <div id ="ui">0</div>
      <div>执行<span id="test">0</span></div>
      <button onclick = "mytest()">常规执行计算任务</button>
      <button onclick = "startRequestIdleCallback()">在requestIdleCallback中执行计算任务</button>
<script>
    // 任务队列
    let task1 = [
        function(){
            for(var i=0;i<3000;i++){
                console.log(i)
            }
            console.log("第一个任务");
            document.getElementById('test').innerHTML = 1
        },
        function(){  
            for(var i=0;i<3000;i++){
                console.log(i)
            }
            console.log("第二个任务");
            document.getElementById('test').innerHTML = 2
        },
        function(){
            for(var i=0;i<3000;i++){
                console.log(i)
            }
            console.log("第三个任务");
            document.getElementById('test').innerHTML = 3
        },
    ];
    let task2 = [
        function(){
            for(var i=0;i<3000;i++){
                console.log(i)
            }
            console.log("第一个任务");
            document.getElementById('test').innerHTML = 1
        },
        function(){  
            for(var i=0;i<3000;i++){
                console.log(i)
            }
            console.log("第二个任务");
            document.getElementById('test').innerHTML = 2
        },
        function(){
            for(var i=0;i<3000;i++){
                console.log(i)
            }
            console.log("第三个任务");
            document.getElementById('test').innerHTML = 3
        },
    ];
    setInterval(() => {
        document.getElementById('ui').innerHTML = parseInt(document.getElementById('ui').innerHTML) + 1
    },100)
    //执行mytest文件会影响上面动态dom的渲染
    function mytest(){
        if (task1.length > 0){
            work1(task1)
        }
    }
    
    //将js计算任务放在requestIdleCallback中运算
    function startRequestIdleCallback(){
        requestIdleCallback(myNonEssentialWork, { timeout: 2000 });
    }
    
    function myNonEssentialWork (deadline) {
        //alert(deadline.timeRemaining())
        console.log(deadline,deadline.timeRemaining())
      // 如果帧内有富余的时间，或者超时
      while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && task2.length > 0) {
        work2(task2);
      }
      //开启下一个空闲时间的回调函数
      if (task2.length > 0){requestIdleCallback(myNonEssentialWork);}
    }
    // ​
    function work1 (tasks) {
      tasks.shift()();
      console.log('执行任务');
      if(task1.length > 0){
        work1(task1)
        
      }
      
    }
    function work2 (tasks) {
      tasks.shift()();
      console.log('执行任务');
    }
    
</script>
</body>
</html>